import fs from "fs";
import path from "path";
import { entityPath, javaPackage, javaRoot, jpr, mapperPath, serviceImplPath, servicePath } from "./config";
const tables: string[] = [];
function uc(s: string) {
  return s.replace(/_\w/g, m => m.toUpperCase()).replace(/_/g, "");
}
function fu(s: string) {
  return s.substring(0, 1).toUpperCase() + s.substring(1);
}
function writeMapper(tableName: string, comment: string) {
  const mp = path.resolve(mapperPath, `${tableName}Mapper.java`),
    xp = path.resolve(mapperPath, `xml/${tableName}Mapper.xml`);
  if (!fs.existsSync(mp)) {
    const mapper = `package ${javaPackage}.mapper;

import ${javaPackage}.entity.${tableName};
import com.baomidou.mybatisplus.core.mapper.BaseMapper;

/**
 * ${comment} Mapper 接口
 * 
 * @author mac-xiang
 */
public interface ${tableName}Mapper extends BaseMapper<${tableName}> {

}`;
    fs.writeFileSync(mp, mapper);
  }
  if (!fs.existsSync(xp)) {
    const xml = `<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="${javaPackage}.mapper.${tableName}Mapper">

</mapper>
`;
    fs.writeFileSync(xp, xml);
  }
}
function readServiceImpl(tableName: string, comment: string) {
  const p = path.resolve(serviceImplPath, `${tableName}ServiceImpl.java`);
  let ret = "";
  if (fs.existsSync(p)) {
    ret = fs.readFileSync(p, "utf8");
  } else {
    ret = `package ${javaPackage}.service.impl;

import java.util.List;

import jakarta.annotation.Resource;

import org.springframework.stereotype.Service;

import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import ${jpr}.api.Util;
import ${javaPackage}.entity.User;
import ${javaPackage}.entity.${tableName};
import ${javaPackage}.mapper.${tableName}Mapper;
import ${javaPackage}.service.${tableName}Service;

/**
 * ${comment} 服务实现类
 * 
 * @author mac-xiang
 */
@Service
public class ${tableName}ServiceImpl extends ServiceImpl<${tableName}Mapper, ${tableName}> implements ${tableName}Service {
  @Resource
  ${tableName}Mapper mapper;

  private QueryWrapper<${tableName}> readWrapper(JSONObject p, User per) {
    QueryWrapper<${tableName}> ret = Util.getQuery(p, ${tableName}.class);
    if (per != null && !per.per("${comment}查询")) {
      // ret.eq("\`create\`", per.id);
    }
    return ret;
  }

  private List<${tableName}> getList(JSONObject p, User per) {
    return mapper.selectList(readWrapper(p, per));
  }

  private Page<${tableName}> getPage(Page<${tableName}> page, JSONObject p, User per) {
    return mapper.selectPage(page == null ? new Page<${tableName}>(1, 100) : page, readWrapper(p, per));
  }

  public ${tableName} create(JSONObject p, User per) {
    if (per != null && per.per("${comment}创建")) {
      ${tableName} entity = Util.getEntity(p, ${tableName}.class);
      // entity.createTime = null;
      // entity.create = per.id;
      mapper.insert(entity);
      return entity;
    }
    throw new RuntimeException("没有权限");
  }

  public int update(JSONObject p, User per) {
    if (per != null && per.per("${comment}修改")) {
      ${tableName} entity = Util.getEntity(p, ${tableName}.class);
      QueryWrapper<${tableName}> qw = Util.getQuery(p, ${tableName}.class);
      if (this.count(qw) > 10) {
        throw new RuntimeException("单次修改数量超过10条");
      }
      // entity.create = null;
      return mapper.update(entity, qw);
    }
    throw new RuntimeException("没有权限");
  }

  public Object read(JSONObject p, User per) {
    Page<${tableName}> page = Util.getPage(p, ${tableName}.class);
    return page == null ? getList(p, per) : getPage(page, p, per);
  }

  public int delete(JSONObject p, User per) {
    if (per != null && per.per("${comment}删除")) {
      QueryWrapper<${tableName}> q = Util.getQuery(p, ${tableName}.class);
      if (this.count(q) > 10) {
        throw new RuntimeException("删除数据的数量不能超过10条");
      }
      return mapper.delete(q);
    }
    throw new RuntimeException("没有权限");
  }

  public long count(JSONObject p, User per) {
    return this.count(readWrapper(p, per));
  }
}
`;
    fs.writeFileSync(p, ret, "utf8");
  }
  return ret;
}
function writeService(tableName: string, comment: string) {
  const p = path.resolve(servicePath, `${tableName}Service.java`),
    si = readServiceImpl(tableName, comment),
    ret = [`package ${javaPackage}.service;

import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.extension.service.IService;
import ${javaPackage}.entity.User;`],
    rc: string[] = [];
  si.match(/\n  public [^ ]+ \w+\([^\{}]+/g)?.forEach(s => {
    s = s.substring(1);
    s.substring(9).replace(/\s+[\w_]+[\(\),]/g, " ").replace(/[<>]/g, " ").split(" ").forEach(type => {
      if (type) {
        const [t] = si.match(new RegExp(`import [\\w\\.]+\\.${type};`)) || [];
        if (t && !ret.includes(t) && ret[0].indexOf(t) < 0) {
          ret.push(t);
        }
      }
    });

    rc.push(s.replace(/(?:\bpublic\s+)|(?:\s$)/g, "") + ";");
  });
  ret.push(`\npublic interface ${tableName}Service extends IService<${tableName}> {\n`, rc.join("\n\n"), "}");
  const d = ret.join("\n");
  if (fs.existsSync(p) && fs.readFileSync(p, { encoding: "utf8" }) == d) {
    return;
  }
  fs.writeFileSync(p, d);
}
function writeStaticMapper() {
  const
    staticMapperPath = path.resolve(javaRoot, "StaticMapper.java"),
    frist = [`package ${javaPackage};\n`,
      "import org.springframework.beans.factory.annotation.Autowired;",
      "import org.springframework.stereotype.Component;"],
    middle = ["\n@Component", "public class StaticMapper {"],
    content: string[] = [];
  tables.forEach(e => {
    frist.push(`import ${javaPackage}.mapper.${e}Mapper;`);
    const el = e.charAt(0).toLowerCase() + e.substring(1);
    content.push(`
  public static ${e}Mapper ${el};

  @Autowired
  public void set${e}(${e}Mapper param) {
    ${el} = param;
  }`);
  });
  frist.push(...middle, ...content, "}");
  const r = frist.join("\n");
  if (!fs.existsSync(staticMapperPath) || r != fs.readFileSync(staticMapperPath, "utf8").replace(/\r/g, "")) {
    fs.writeFileSync(staticMapperPath, r, "utf8");
  }
}
function writeStaticService() {
  const
    staticServicePath = path.resolve(javaRoot, "StaticService.java"),
    frist = [`package ${javaPackage};\n`,
      "import java.util.List;",
      "import org.springframework.beans.factory.annotation.Autowired;",
      "import org.springframework.stereotype.Component;",
      "import com.xiang.api.Util;"],
    middle = `
@Component
public class StaticService {

  public static <T> List<T> selectSql(String sql, Class<T> clazz) {
    return Util.toArray(Util.toJString(StaticSql.run.select(sql)), clazz);
  }`,
    content: string[] = [];
  tables.forEach(e => {
    frist.push(`import ${javaPackage}.service.${e}Service;`);
    const el = e.charAt(0).toLowerCase() + e.substring(1);
    content.push(`
  public static ${e}Service ${el};

  @Autowired
  public void set${e}(${e}Service param) {
    ${el} = param;
  }`);
  });
  frist.push(middle, ...content, "}");
  const r = frist.join("\n");
  // console.log(r == fs.readFileSync(staticServicePath, "utf8").replace(/\r/g, ""));
  if (!fs.existsSync(staticServicePath) || r != fs.readFileSync(staticServicePath, "utf8").replace(/\r/g, "")) {
    fs.writeFileSync(staticServicePath, r, "utf8");
  }
}
function writeService2(tableName: string, comment: string) {
  const p = path.resolve(servicePath, `${tableName}Service.java`);
  if (!fs.existsSync(p)) {
    const ret = `package ${javaPackage}.service;

import java.util.List;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import ${jpr}.api.Util;
import ${javaPackage}.entity.User;
import ${javaPackage}.entity.${tableName};
import ${javaPackage}.mapper.${tableName}Mapper;

/**
 * ${comment} 服务类
 * 
 * @author mac-xiang
 */
@Service
public class ${tableName}Service extends ServiceImpl<${tableName}Mapper, ${tableName}> {
  @Resource
  ${tableName}Mapper mapper;

  private QueryWrapper<${tableName}> readWrapper(JSONObject p, User per) {
    QueryWrapper<${tableName}> ret = Util.getQuery(p, ${tableName}.class);
    if (per != null && !per.per("${comment}查询")) {
      // ret.eq("\`create\`", per.id);
    }
    return ret;
  }

  private List<${tableName}> getList(JSONObject p, User per) {
    return mapper.selectList(readWrapper(p, per));
  }

  private Page<${tableName}> getPage(Page<${tableName}> page, JSONObject p, User per) {
    return mapper.selectPage(page == null ? new Page<${tableName}>(1, 100) : page, readWrapper(p, per));
  }

  public ${tableName} create(JSONObject p, User per) {
    if (per != null && per.per("${comment}创建")) {
      ${tableName} entity = Util.getEntity(p, ${tableName}.class);
      // entity.createTime = null;
      // entity.create = per.id;
      mapper.insert(entity);
      return entity;
    }
    throw new RuntimeException("没有权限");
  }

  public int update(JSONObject p, User per) {
    if (per != null && per.per("${comment}修改")) {
      ${tableName} entity = Util.getEntity(p, ${tableName}.class);
      QueryWrapper<${tableName}> qw = Util.getQuery(p, ${tableName}.class);
      if (this.count(qw) > 10) {
        throw new RuntimeException("单次修改数量超过10条");
      }
      // entity.create = null;
      return mapper.update(entity, qw);
    }
    throw new RuntimeException("没有权限");
  }

  public Object read(JSONObject p, User per) {
    Page<${tableName}> page = Util.getPage(p, ${tableName}.class);
    return page == null ? getList(p, per) : getPage(page, p, per);
  }

  public int delete(JSONObject p, User per) {
    if (per != null && per.per("${comment}删除")) {
      QueryWrapper<${tableName}> q = Util.getQuery(p, ${tableName}.class);
      if (this.count(q) > 10) {
        throw new RuntimeException("删除数据的数量不能超过10条");
      }
      return mapper.delete(q);
    }
    throw new RuntimeException("没有权限");
  }

  public long count(JSONObject p, User per) {
    return this.count(readWrapper(p, per));
  }
}
`;
    fs.writeFileSync(p, ret, "utf8");
  }
}
export function apiSql(/** 文件完整路径 */p: string) {
  tables.splice(0);
  fs.readFileSync(p, { encoding: "utf8" }).replace(/\r/ig, "").match(/CREATE TABLE [^;]+/gm)?.forEach(s => {
    const [, table, tableComment] = s.match(/CREATE TABLE `(\w+)`[\s\S]+comment\s*=\s*'(.+)'\s*engine\s*=/i) as string[],
      tableName = fu(uc(table)),
      entityFilePath = path.resolve(entityPath, `${tableName}.java`);
    if (!fs.existsSync(entityFilePath)) {
      const entity = `package ${javaPackage}.entity;

import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableField;
import java.io.Serializable;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import lombok.EqualsAndHashCode;

/**
 * ${tableComment} 数据实体
 * 
 * @author mac-xiang
 */
@Data
@EqualsAndHashCode(callSuper = false)
@TableName(value = "\`${table}\`", autoResultMap = true)
@ApiModel(value = "${tableComment} 对象", description = "${tableComment}")
public class ${tableName} implements Serializable {

  private static final long serialVersionUID = 1L;
`,
        res: string[] = [];
      s.match(/`(\w+)`\s+(\w+)[^\n]+/g)?.forEach(ts => {
        const name = (ts.match(/`(\w+)`/)?.[1]) as string,
          tsl = ts.toLowerCase(),
          type = tsl.indexOf("int") > 0 ? (tsl.indexOf("unsigned") > 0 ? "Long" : "Integer") : "String",
          comment = ts.match(/comment\s+'([^']+)/i)?.[1] || name,
          def = ts.match(/default\s+'?([^'\s]+)/i)?.[1] || "",
          f = name.toLowerCase() != "id",
          ins = def ? "" : (f ? ", fill = FieldFill.INSERT" : ", type = IdType.ASSIGN_ID");
        res.push(`  /** ${comment} */
  @Table${f ? "Field" : "Id"}(value = "${f ? `\`${name}\`` : name}"${ins})
  public ${type} ${uc(name)};`);
      });
      fs.writeFileSync(entityFilePath, entity + res.join("\n\n") + `\n\n  public ${tableName}() {\n  }\n}`);
      writeMapper(tableName, tableComment);
      writeService2(tableName, tableComment);
    }
    tables.push(tableName);
  });
  tables.sort();
  writeStaticMapper();
  writeStaticService();
  // console.log(tables);
}


export function jssic(/** 文件完整路径 */p: string,) {
  let a = p.lastIndexOf("\\"), b = p.lastIndexOf("/");
  if (a < b) { a = b; }
  a++; b = p.lastIndexOf("ServiceImpl.java");
  const s = p.substring(a, b),
    c = fs.readFileSync(p, { encoding: "utf8" }).match(/\*\s+([^\s]+)\s+服务实现类/)?.[1];
  if (c) {
    writeService2(s, c);
  } else {
    console.error("没有找到注释", p);

  }
}
